from rest_framework import serializers

from demo.models import Student, Classes

'''
序列化器的序列化与反序列化
后端到前端 提交实例化对象(instance) 需要转成JSON数据(data)给前端进行渲染操作 -序列化
前端到后端 提交JSON数据(data) 需要转成实例化对象(instance)给后端进行持久化操作 -反序列化
'''

'''
命名规范：
    模型类+Serializer

属性要求：
    将需要返回或提交的模型字段 定义为序列化器的属性，
    一般来说序列化器的属性与模型字段一一对应
    不想展示的数据可以注释掉

重写方法：
    序列化器内需要重写方法进行增删改查的一些操作
'''


# class StudentSerializer(serializers.Serializer):
#     # read_only 只读
#     id = serializers.IntegerField(label="ID",read_only=True)
#     name = serializers.CharField(max_length=30,label="姓名")
#     # required= False 表示提交数据时 不是必填项
#     age = serializers.IntegerField(required=False, label="年龄")
#     # 性别由0或1 转成 女、男 所以这里是Integer字段就好
#     sex = serializers.IntegerField(required=False,label="性别")
#     create_time = serializers.DateTimeField(required=False, label="创建时间")
#
#     update_time = serializers.DateTimeField(required=False, label="修改时间")
#     is_delete = serializers.BooleanField(required=False, default=False, label="逻辑删除")
#
#     def create(self, validated_data):
#         # validated_data是前端想传到后端的数据
#         # 调用模型类的create方法做持久化操作
#         return Student.objects.create(**validated_data)
#
#     def update(self, instance, validated_data):
#         # [键]取值方式 如果不存在会报错
#         # get方法可以自定义返回的值，键有对应的值，则返回值，如果没有则返回后面自定义的内容
#
#         # 获取name键对应的值，如果有的话代表修改了用户名，得到新的用户名
#         # 获取name键对应的值，如果没有则代表没有修改用户名，使用数据表里面原本的值
#         instance.name = validated_data.get("name", instance.name)
#         instance.age = validated_data.get("age", instance.age)
#         instance.sex = validated_data.get("sex", instance.sex)
#         # 通过模型对象做保存的操作 持久化数据
#         instance.save()
#         return instance

# 序列化器的简化写法
class StudentSerializer(serializers.ModelSerializer):
    # 添加想要显示的字段 classes.name
    # 把模型的值作为属性来源
    # 添加额外的字段
    class_name = serializers.CharField(source='classes.name', read_only=True)

    # Meta 元数据类 数据来源模型是那个模型
    # 一些基本的数据校验
    class Meta:
        # 选取数据来源
        model = Student
        # 指定映射的字段，fields='__all__'映射所有的字段，都会展示出来
        # fields = '__all__'
        # 列表指定只展示该两个字段给前端显示
        # fields = ["name","age"]
        # 除去选择的字段不显示，其他都显示
        exclude = ["is_delete"]

        # 添加数据校验
        extra_kwargs = {
            "age": {
                "min_value": 1,
                "max_value": 150,
            },
            # 限制班级为只写操作
            'classes': {'write_only': True}
        }

    # 编写方法校验前端提交的字段
    # validate_你要校验的字段名
    # 属性级别的校验
    # def validate_name(self, value):
    #     if 'drf' not in value.lower():
    #         # 如果drf不在提交的数据中 就抛出异常
    #         raise serializers.ValidationError("用户名需要包含drf")
    #     # 返回校验通过的值
    #     return value

    # 对象级别的校验
    # 把用户提交的所有数据传入到参数，字典类型
    # 可以一次性对多个字段进行校验 联动校验
    def validate(self, attrs):
        # 取字段校验的方式 attrs.get('字段名')
        # if 'drf' not in attrs.get('name').lower():
        #     raise serializers.ValidationError("用户名需要包含drf")

        if attrs.get('age') < 18:
            raise serializers.ValidationError("年龄需要大于等于18")
        return attrs


# 作为中间序列化器来给ClassSerializer调用
class StudentSerializerSimple(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = ["id", "name", "age", "sex"]


class ClassesSerializer(serializers.ModelSerializer):
    # 添加一个额外的字段
    # 属性名就是管理器的名字
    # 把该班级的所有学生使用 StudentSerializer序列化器，进行序列化的操作
    # 用模型管理器student_set保存
    # 序列化器的嵌套 在一个序列化器里面使用另一个序列化器
    student_set = StudentSerializerSimple(many=True,read_only=True)

    class Meta:
        model = Classes
        exclude = ["is_delete"]
